package com.smart.common.config.datasource;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.alicp.jetcache.Cache;
import com.smart.common.annotation.DictTranslator;
import com.smart.common.entities.option.SelectOption;
import com.smart.common.entities.option.SelectOptionMap;
import com.smart.manager.system.repository.DictRepository;
import io.ebean.event.BeanPostLoad;
import lombok.extern.log4j.Log4j2;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * 注册一个数据字典拦截器
 *
 * @author Xiaxuqiu
 * @date 2022-08-09
 **/
@Log4j2
public class EbeanDictPostLoad implements BeanPostLoad {


    private final DictRepository dictRepository;
    private final Cache<String, List<SelectOptionMap>> dictCache;

    public EbeanDictPostLoad(DictRepository dictRepository, Cache<String, List<SelectOptionMap>> dictCache) {
        this.dictRepository = dictRepository;
        this.dictCache = dictCache;
    }


    /**
     * 判断当前类是否需要开启拦截器
     *
     * @param aClass 一个类
     * @return boolean
     */
    @Override
    public boolean isRegisterFor(Class<?> aClass) {
        String dictTypeName = SelectOption.class.getName();
        Field[] fieldArr = ReflectUtil.getFields(aClass);
        for (Field field : fieldArr) {
            String filedTypeName = field.getType().getTypeName();
            DictTranslator translator = field.getAnnotation(DictTranslator.class);
            if (ObjectUtil.isNotEmpty(translator) && filedTypeName.equals(dictTypeName)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void postLoad(Object object) {

        String clsName = object.getClass().getName();

        String dictTypeName = SelectOption.class.getName();
        Field[] fieldArr = ReflectUtil.getFields(object.getClass());
        // 批量抓取数据

        List<SelectOptionMap> dictRs = getDictRs(clsName, fieldArr);


        for (Field field : fieldArr) {
            String filedTypeName = field.getType().getTypeName();
            DictTranslator translator = field.getAnnotation(DictTranslator.class);
            if (translator == null) {
                // 注解不正确或者当前的数据类型不是数据字典类型 那么直接跳过
                continue;
            }


            if (!filedTypeName.equals(dictTypeName)) {
                log.error(field.getName() + "数据字典对应的类型不正确");
                continue;
            }

            String sourceField = StrUtil.isBlank(translator.sourceField()) ? field.getName().replace("Decode", "") : translator.sourceField();
            //统一转小写
            String dictCode = StrUtil.isBlank(translator.dictCode()) ? sourceField : translator.dictCode();
            //判断是否存在目标指端

            Optional<Field> targetField = Arrays.stream(fieldArr).filter(x -> x.getName().equals(sourceField)).findFirst();
            if (targetField.isPresent()) {
                //目标字段上的值
                Object value = ReflectUtil.getFieldValue(object, targetField.get());
                Optional<SelectOptionMap> optSelectList = dictRs.stream().filter(x -> dictCode.equals(x.getKeyword())).findFirst();
                //当来源字段的值不为空时 才去翻译字典
                if (ObjectUtil.isNotEmpty(value) && optSelectList.isPresent()) {
                    // 判断是否存在目标值
                    Optional<SelectOption> hasResult = optSelectList.get().getItems().stream().filter(x -> x.getValue().equals(value.toString())).findFirst();
                    // 存在目标值 那么将获得的对象赋值到目标字段
                    hasResult.ifPresent(x -> ReflectUtil.setFieldValue(object, field, x));
                }
            } else {
                log.warn("没有匹配到数据字典字段:{}", sourceField);
            }
        }
    }


    private List<SelectOptionMap> getDictRs(String clsName, Field[] fieldArr) {
        String cacheKey = DigestUtil.md5Hex16(clsName);
        List<SelectOptionMap> selectOptionMaps = dictCache.get(cacheKey);
        if (selectOptionMaps != null) {
            return selectOptionMaps;
        }
        ArrayList<String> dictCodes = new ArrayList<>();
        for (Field field : fieldArr) {
            String filedTypeName = field.getType().getTypeName();
            DictTranslator translator = field.getAnnotation(DictTranslator.class);
            // 注解不正确或者当前的数据类型不是数据字典类型 那么直接跳过
            if (translator == null) {
                continue;
            }
            if (!filedTypeName.equals(SelectOption.class.getName())) {
                log.error(field.getName() + "数据字典对应的类型不正确");
                continue;
            }
            String sourceField = StrUtil.isBlank(translator.sourceField()) ? field.getName().replace("Decode", "") : translator.sourceField();
            String dictCode = StrUtil.isBlank(translator.dictCode()) ? sourceField : translator.dictCode();
            dictCodes.add(dictCode);
        }
        List<SelectOptionMap> rs = dictRepository.batchReadDict(dictCodes);
        dictCache.put(cacheKey, rs);
        return rs;
    }
}

